/**
Copyright 2011 Steven Moxley

This file is part of Joggle.

Joggle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Joggle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Joggle.  If not, see <http://www.gnu.org/licenses/>.
 */
package edu.gwu.cs.joggle;

import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.ArrayList;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

import com.almworks.sqlite4java.SQLiteException;

/**
 * @author      Steven Moxley <steven.moxley@gmail.com>
 * @version     1             
 * @since       2011-12-20
 */
public class Client
{
	protected Server server;
	protected String id;
	protected User user;
	protected GUI gui;

	protected Server getServer() {
		return server;
	}

	/**
	 * @return Integer The ID number assigned by the Server
	 */
	protected String getID() {
		return id;
	}

	/**
	 * @param id Sets (overwrites) the ID number assigned by the Server
	 * @throws Consider throwing an Exception if the method is invoked by someone other than the Server or Administrator
	 */
	protected void setID(String id) {
		this.id = id;
	}

	/**
	 * @return User The Player currently authenticated by this Client
	 * @throws May be null if no Player has logged in
	 */
	protected User getUser() {
		return user;
	}

	/**
	 * @param msg Send a basic message to this Client's Server
	 * @deprecated TESTING: This method should be replaced by network/socket communication
	 */
	protected void sendServerMessage(String msg) {
        try {
            SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
            SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("localhost", 7066);

            OutputStream outputstream = sslsocket.getOutputStream();
            OutputStreamWriter outputstreamwriter = new OutputStreamWriter(outputstream);
            BufferedWriter bufferedwriter = new BufferedWriter(outputstreamwriter);

            bufferedwriter.write(msg + '\n');
            bufferedwriter.flush();
        } catch (Exception exception) {
            exception.printStackTrace();
        }
	}

	/**
	 * @param msg Invoked by Server to send this Client a message
	 * @deprecated TESTING: This method should be replaced by network/socket communication
	 */
	protected void receiveServerMessage(String msg) {
		if(!msg.equals("kthx")) {
			System.out.println();
			System.out.println("The server said:");
			System.out.println(msg);
			System.out.println();
			sendServerMessage("kthx");
		}
	}

	/**
	 * Create a Client interface for a Player to login.  Change as needed or replace for network communication and GUI
	 * @param s Server
	 * @throws SQLiteException 
	 */
	protected Client(Server s) throws SQLiteException {
		server = s;
		id = server.hash("Java Version: " + System.getProperty("java.version") + "\nOS Architecture: " + System.getProperty("os.arch") + "\nOS Name: " + System.getProperty("os.name") + "\nOS Version: " + System.getProperty("os.version") + "\nCurrent Time: " + System.currentTimeMillis());
		// ping the server by adding yourself as a client
		s.addClient(this);	

		gui = new GUI(server);
	}

	/**
	 * Create a Client interface for an authenticated Player.  Change as needed or replace for network communication and GUI
	 * @param s Serer
	 * @param u User
	 */
	protected Client(Server s, User u) {
		server = s;
		user = u;

		gui = new GUI(server);
	}

    public static void secureMessage(String message)
    {
        try
        {
            SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
            SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("localhost", 7066);

            OutputStream outputstream = sslsocket.getOutputStream();
            OutputStreamWriter outputstreamwriter = new OutputStreamWriter(outputstream);
            BufferedWriter bufferedwriter = new BufferedWriter(outputstreamwriter);

            bufferedwriter.write(message + '\n');
            bufferedwriter.flush();
        }
        catch(Throwable e)
        {
            e.printStackTrace();
        }
    }

	/**
	 * @param args TESTING PLAYGROUND: Used to instantiate Objects for testing, debugging
	 * @throws SQLiteException 
	 * @throws IOException 
	 */
	public static void main(String[] args) throws SQLiteException, IOException
	{
        // send a secure message to the server

        System.out.println("sending message to server");
        secureMessage("attack at dawn");

		Administrator serverAdmin = new Administrator("Super", "User", "superman", "admin@gmail.com", "password123");
		Server server = new Server(serverAdmin, 256, "/Users/steve/workspace/gwu-csci6531-team2-joggle/assets/dictionaries/");
		//Server server = new Server(serverAdmin, 256, "/Users/kneugent/GWU/CS6531/gwu-csci6531-team2-joggle/assets/dictionaries/");
		//Server server = new Server(serverAdmin, 256, (ClassLoader.getSystemResource("assets/dictionaries/")).toString());
		System.out.println();
		Client client = new Client(server);
		Auditor a1 = new Auditor("Inspector", "General", "auditor", "rjfala@aodlkfja.com", "password123", new ArrayList<Game>(), new ArrayList<Player>(), server, serverAdmin, true);

		Player player1 = new Player("Steven", "Moxley", "smoxley", "smoxley@gwu.edu", "password123", 1, server, true);		
		a1.addAuthorizedPlayer((Player) server.getUserFromName("smoxley", "Player", "password123"));
		/*
		Player player2 = new Player("Silly", "Opponent", "example", "silly@aol.com", "password123", 0, server, true);
		Player player3 = new Player("Testing", "Account", "test", "test@website.com", "", 2, server, true);
		Player player4 = new Player("Dummy", "Account", "demo", "test@website.com", "password123", 0, server, true);
		Client player1Client = new Client(server, player1);

		System.out.println("Player1 can see Player2's profile because it's public:");
		player2.getProfile(player1);
		System.out.println();

		System.out.println("Player1 can see his own profile even though it's private because he owns it:");
		player1.getProfile(player1);
		System.out.println();

		System.out.println("Player2 cannot see Player1's profile because it's private and he's not authorized:");
		player1.getProfile(player2);
		System.out.println();
		
		player1.addFriend(player2);
		player1.addFriend(player3);
		System.out.println("Is Player2 now Player1's friend? " + player1.isFriend(player2));
		System.out.println("Is Player1 now Player2's friend? " + player2.isFriend(player1));
		System.out.println();
		System.out.println("After becoming friends, Player2 can now see Player1's profile because he's in Player1's ACL:");
		player1.getProfile(player2);
		System.out.println();
		
		System.out.println("Is Player3 now Player1's friend? " + player1.isFriend(player3));
		System.out.println("Is Player1 now Player3's friend? " + player3.isFriend(player1));
		System.out.println("Even though Player1 and Player3 are friends, Player1 cannot see Player3's profile because it is restricted:");
		player3.getProfile(player1);
		System.out.println();
		
		Game joggle = player1.createGame();
		ArrayList<String> banned = new ArrayList<String>();
		//banned.add(player3.getUserName());
		Game joggle2 = player4.createGame(3, 6, 250, 50000, 2, 2, 0, 4, new ArrayList<String>(), new ArrayList<String>(), banned, player4);
		System.out.println();
		System.out.println("The Server can now advertise a Game was created:");
		ArrayList<Game> active = server.getActiveGames();
		System.out.println("Found " + active.size() + " game(s)");
		for(Game g : active) {
			System.out.println(g);
		}
		System.out.println();
		
		player2.joinGame(joggle);
		System.out.println("Is Player 2 in a Game? " + server.isPlayerInGame(player2));
		//player3.joinGame(joggle2);
		System.out.println("Is Player 3 in a Game? " + server.isPlayerInGame(player3));
		System.out.println();
		
		// test dictionary
		/*
		ArrayList<String> testWords = new ArrayList<String>();
		testWords.add("aa");
		testWords.add("a");
		testWords.add("akh");
		testWords.add("test");
		testWords.add("aardvark");
		System.out.println("There are " + joggle.getDictionary().getSize() + " words in this Game's Dictionary.");
		System.out.println("Of the " + testWords.size() + " words you guessed, " + joggle.getDictionary().binarySearch(testWords).size() + " words were found in this Game's Dictionary.");
		System.out.println();
		
		// server's Administrator creates an Auditor authorized to audit the above game and one of its Players
		ArrayList<Game> authedGames = new ArrayList<Game>();
		authedGames.add(joggle);
		authedGames.add(joggle2);
		ArrayList<Player> authedPlayers = new ArrayList<Player>();
		authedPlayers.add(player2);
		/*
		Auditor a1 = new Auditor("Inspector", "General", "auditor", "rjfala@aodlkfja.com", "password123", authedGames, authedPlayers, server, serverAdmin, true);
		
		// review game
		try {
			a1.reviewGame(joggle);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		System.out.println();
		
		try {
			a1.reviewGame(joggle2);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		
		System.out.println();
		// review unauthorized player
		try {
			a1.reviewPlayer(player1);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		System.out.println();
		// review authorized player
		try {
			a1.reviewPlayer(player2);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		System.out.println();
		
		System.out.println("The Server should now advertise only one game:");
		active = server.getActiveGames();
		System.out.println("Found " + active.size() + " game(s)");
		for(Game g : active) {
			System.out.println(g);
		}
		System.out.println();
		
		// test getting users different ways
		/*
		System.out.println("Got Auditor with getAuditorFromName():\t" + server.getAuditorFromName("auditor").toString());
		System.out.println("Got Admin with getAdminFromName():\t" + server.getAdminFromName("superman").toString());
		System.out.println("Got Auditor with getUserFromName():\t" + server.getUserFromName("auditor", "Auditor").toString());
		System.out.println("Got Admin with getUserFromName():\t" + server.getUserFromName("superman", "Administrator").toString());
		System.out.println();
		ArrayList<User> users = server.getAllUsers();
		System.out.println("All users in the database:");
		for(User u: users) { System.out.println(u); }
		System.out.println();
		*/
        //authedClient.sendServerMessage("derp");
	}
}
